package com.ruicar.afs.cloud.bizcommon.rules.util;

import com.alibaba.fastjson.JSON;
import com.ruicar.afs.cloud.bizcommon.dto.rules.tree.RuleTreeDto;
import com.ruicar.afs.cloud.bizcommon.dto.rules.tree.RuleTreeExpressDto;
import com.ruicar.afs.cloud.bizcommon.enums.rules.AtomComponentType;
import com.ruicar.afs.cloud.bizcommon.enums.rules.RuleItemType;
import com.ruicar.afs.cloud.bizcommon.enums.rules.RuleTreeExpressType;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.List;
import java.util.Map;


@UtilityClass
@Slf4j
public class RuleConfigUtil {
    private final String BLANK_STR = " ";
    private final String LIKE = "like";
    private final String IN = "in";

    public List<RuleTreeDto> genRuleItemTree(String itemData) {
        List<RuleTreeDto> treeDtoList = JSON.parseArray(itemData, RuleTreeDto.class);
        return treeDtoList;
    }

    public String genRuleRunExpress(List<RuleTreeDto> treeDtoList, Map<String, String> atomKeyMapping) {

        if (treeDtoList == null || treeDtoList.size() == 0) {
            return "";
        }
        StringBuffer stringBuffer = new StringBuffer();
        //if else 类型
        if (RuleItemType.CHOICE.equals(treeDtoList.get(0).getType())) {
            for (int i = 0; i < treeDtoList.size(); i++) {
                stringBuffer.append(processChoiceItem(treeDtoList.get(i), atomKeyMapping));
            }
            stringBuffer.append(BLANK_STR);
            stringBuffer.append("return false;");
        } else if (RuleItemType.EXPRESS.equals(treeDtoList.get(0).getType())) {
            stringBuffer.append(BLANK_STR);
            stringBuffer.append("if(");
            for (int i = 0; i < treeDtoList.size(); i++) {
                stringBuffer.append(processItem(i, treeDtoList.get(i), atomKeyMapping));
            }

            stringBuffer.append(") then {return true;} else { return false;}");
        }
        return stringBuffer.toString();
    }


    private String processChoiceItem(RuleTreeDto ruleTreeDto, Map<String, String> atomKeyMapping) {
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append(BLANK_STR);
        stringBuffer.append("if(");
        stringBuffer.append(processConditionItem(ruleTreeDto.getRows().get(0), atomKeyMapping));
        stringBuffer.append(")");
        stringBuffer.append(BLANK_STR);
        stringBuffer.append("then { ");
        stringBuffer.append(processThenItem(ruleTreeDto.getRows().get(1), atomKeyMapping));
        stringBuffer.append(" }");
        return stringBuffer.toString();
    }

    private String processConditionItem(RuleTreeDto ruleTreeDto, Map<String, String> atomKeyMapping) {
        StringBuffer stringBuffer = new StringBuffer();
        if (RuleItemType.EXPRESS.equals(ruleTreeDto.getType())) {
            for (int i = 0; i < ruleTreeDto.getRows().size(); i++) {
                stringBuffer.append(processItem(i, ruleTreeDto.getRows().get(i), atomKeyMapping));
            }
        } else if (RuleItemType.CONDITION.equals(ruleTreeDto.getType())) {
            stringBuffer.append(processExpress(ruleTreeDto.getExpress(), atomKeyMapping));
        }
        return stringBuffer.toString();
    }


    private String processThenItem(RuleTreeDto ruleTreeDto, Map<String, String> atomKeyMapping) {
        StringBuffer stringBuffer = new StringBuffer();
        stringBuffer.append("if(");
        if (RuleItemType.EXPRESS.equals(ruleTreeDto.getType())) {
            for (int i = 0; i < ruleTreeDto.getRows().size(); i++) {
                stringBuffer.append(processItem(i, ruleTreeDto.getRows().get(i), atomKeyMapping));
            }
        } else if (RuleItemType.THEN.equals(ruleTreeDto.getType())) {
            stringBuffer.append(processExpress(ruleTreeDto.getExpress(), atomKeyMapping));
        }
        stringBuffer.append(") then {return true;} else { return false;}");
        return stringBuffer.toString();
    }

    private String processItem(int index, RuleTreeDto treeDto, Map<String, String> atomKeyMapping) {
        StringBuffer stringBuffer = new StringBuffer();
        switch (treeDto.getType()) {
            case EXPRESS: {
                if (index > 0) {
                    stringBuffer.append(BLANK_STR);
                    stringBuffer.append(treeDto.getKey());
                    stringBuffer.append(BLANK_STR);
                }

                testNot(treeDto, stringBuffer);
                stringBuffer.append("(");
                if (treeDto.getRows() != null && treeDto.getRows().size() > 0) {
                    for (int i = 0; i < treeDto.getRows().size(); i++) {
                        stringBuffer.append(processItem(i, treeDto.getRows().get(i), atomKeyMapping));
                    }
                }
                stringBuffer.append(")");
                break;
            }
            case OR:
            case AND: {
                if (index > 0) {
                    stringBuffer.append(BLANK_STR);
                    stringBuffer.append(treeDto.getKey());
                    stringBuffer.append(BLANK_STR);
                }
                stringBuffer.append(processLogicItem(treeDto, atomKeyMapping));
                break;
            }
            default:
                break;

        }
        return stringBuffer.toString();
    }

    private String processLogicItem(RuleTreeDto treeDto, Map<String, String> atomKeyMapping) {
        StringBuffer stringBuffer = new StringBuffer();
        testNot(treeDto, stringBuffer);
        stringBuffer.append("(");
        stringBuffer.append(processExpress(treeDto.getExpress(), atomKeyMapping));
        stringBuffer.append(")");
        return stringBuffer.toString();
    }

    private String processExpress(RuleTreeExpressDto express, Map<String, String> atomKeyMapping) {
        StringBuffer stringBuffer = new StringBuffer();
        if (express == null ||
                express.getLeft() == null ||
                express.getLeft().getType() == null ||
                express.getOperator() == null ||
                StringUtils.isEmpty(express.getOperator().getValue()) ||
                express.getRight() == null ||
                express.getLeft().getType() == null) {
            return stringBuffer.toString();
        }
        switch (express.getLeft().getType()) {
            case EXPRESS: {
                stringBuffer.append("(");
                stringBuffer.append(processExpress(express.getLeft().getExpress(), atomKeyMapping));
                stringBuffer.append(")");
                break;
            }
            case ATOM: {
                stringBuffer.append(atomKeyMapping.get(express.getLeft().getAtom().getKey()));
                break;
            }
            default:
                break;
        }


        stringBuffer.append(BLANK_STR);
        stringBuffer.append(express.getOperator().getValue());
        stringBuffer.append(BLANK_STR);

        switch (express.getRight().getType()) {
            case EXPRESS: {
                stringBuffer.append("(");
                stringBuffer.append(processExpress(express.getRight().getExpress(), atomKeyMapping));
                stringBuffer.append(")");
                break;
            }
            case ATOM: {
                stringBuffer.append(atomKeyMapping.get(express.getRight().getAtom().getKey()));
                break;
            }
            case VALUE: {
                if (LIKE.equals(express.getOperator().getKey())) {
                    stringBuffer.append("'%");
                    stringBuffer.append(express.getRight().getValue());
                    stringBuffer.append("%'");
                } else if (IN.equals(express.getOperator().getKey())) {
                    stringBuffer.append("(");
                    if (express.getLeft().getType().equals(RuleTreeExpressType.EXPRESS)) {
                        stringBuffer.append("'");
                        stringBuffer.append(express.getRight().getValue().replaceAll(",", "','"));
                        stringBuffer.append("'");
                    } else {
                        //非数字需添加引号
                        if (express.getLeft().getAtom().getComponent().equals(AtomComponentType.NUMBER)) {
                            if ("percentage".equals(express.getLeft().getAtom().getComponentConfig().getString("type"))) {
                                stringBuffer.append(express.getRight().getValue())
                                        .append("/")
                                        .append("100");
                            } else {
                                stringBuffer.append(express.getRight().getValue());
                            }
                        } else {
                            stringBuffer.append("'");
                            stringBuffer.append(express.getRight().getValue().replaceAll(",", "','"));
                            stringBuffer.append("'");
                        }
                    }
                    stringBuffer.append(")");
                } else {
                    if (express.getLeft().getType().equals(RuleTreeExpressType.EXPRESS)) {
                        stringBuffer.append(express.getRight().getValue());
                    } else {
                        //非数字需添加引号
                        if (express.getLeft().getAtom().getComponent().equals(AtomComponentType.NUMBER)) {
                            if ("percentage".equals(express.getLeft().getAtom().getComponentConfig().getString("type"))) {
                                stringBuffer.append(express.getRight().getValue())
                                        .append("/")
                                        .append("100");
                            } else {
                                stringBuffer.append(express.getRight().getValue());
                            }
                        } else {
                            stringBuffer.append("'");
                            stringBuffer.append(express.getRight().getValue());
                            stringBuffer.append("'");
                        }
                    }
                }
            }
            default:
                break;
        }

        return stringBuffer.toString();
    }

    private void testNot(RuleTreeDto treeDto, StringBuffer stringBuffer) {
        if (treeDto.isNot()) {
            stringBuffer.append("!");
        }
    }
}
